Hooking the keyboard message queue in compact framework code
Here is some nice code to use a keyboard hook implemented in C# for compact framework.
You can use this to catch the funny OS asigned keys like F1, F2, F3, F4, F6 and F7 (Softkey 1 and 2, Phone, End, Volume Up, Volume Down); and last but not least catch the Win Key press.
The hooking class:
using System; using System.Runtime.InteropServices; /* In order to use this class in your program, just declare the varialble and hook up into HookEvent: HookKeys hook = new HookKeys(); hook.HookEvent += new HookKeys.HookEventHandler(HookEvent); hook.Start(); */ public class HookKeys { #region delegates public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam); public delegate void HookEventHandler(HookEventArgs e, KeyBoardInfo keyBoardInfo); public HookEventHandler HookEvent; #endregion #region fields private HookProc hookDeleg; private static int hHook = 0; #endregion public HookKeys() { } ~HookKeys(){ if(hHook!=0) this.Stop(); } #region public methods /// /// Starts the hook /// public void Start() { if (hHook != 0) { //Unhook the previouse one this.Stop(); } hookDeleg = new HookProc(HookProcedure); hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookDeleg, GetModuleHandle(null), 0); if (hHook == 0) { throw new SystemException("Failed acquiring of the hook."); } AllKeys(true); } /// /// Stops the hook /// public void Stop() { UnhookWindowsHookEx(hHook); AllKeys(false); } #endregion #region protected and private methods protected virtual void OnHookEvent(HookEventArgs hookArgs, KeyBoardInfo keyBoardInfo) { if (HookEvent != null) { HookEvent(hookArgs, keyBoardInfo); } } private int HookProcedure(int code, IntPtr wParam, IntPtr lParam) { KBDLLHOOKSTRUCT hookStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT)); if (code < 0) return CallNextHookEx(hookDeleg, code, wParam, lParam); // Let clients determine what to do HookEventArgs e = new HookEventArgs(); e.Code = code; e.wParam = wParam; e.lParam = lParam; KeyBoardInfo keyInfo = new KeyBoardInfo(); keyInfo.vkCode = hookStruct.vkCode; keyInfo.scanCode = hookStruct.scanCode; OnHookEvent(e, keyInfo); // Yield to the next hook in the chain return CallNextHookEx(hookDeleg, code, wParam, lParam); } #endregion #region P/Invoke declarations [DllImport("coredll.dll")] private static extern int AllKeys(bool bEnable); [DllImport("coredll.dll")] private static extern int SetWindowsHookEx(int type, HookProc hookProc, IntPtr hInstance, int m); [DllImport("coredll.dll")] private static extern IntPtr GetModuleHandle(string mod); [DllImport("coredll.dll")] private static extern int CallNextHookEx( HookProc hhk, int nCode, IntPtr wParam, IntPtr lParam ); [DllImport("coredll.dll")] private static extern int GetCurrentThreadId(); [DllImport("coredll.dll", SetLastError = true)] private static extern int UnhookWindowsHookEx(int idHook); private struct KBDLLHOOKSTRUCT { public int vkCode; public int scanCode; public int flags; public int time; public IntPtr dwExtraInfo; } const int WH_KEYBOARD_LL = 20; #endregion } #region event arguments public class HookEventArgs : EventArgs { public int Code; // Hook code public IntPtr wParam; // WPARAM argument public IntPtr lParam; // LPARAM argument } public class KeyBoardInfo { public int vkCode; public int scanCode; public int flags; public int time; } #endregion
Here is the download of the Visual Studio 2005 Windows Mobile 6 SDK targeting source code:
[Download not found]Update 20. sept 2019:
Better code which will start/stop the hook with Activate/Deactivate (Show/Minimize) of a form:
using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace HookCEtest { public partial class Form1 : Form { HookKeys hook; public Form1() { InitializeComponent(); // Inizialize keyboard hook event handler. Calls "HookEvent" method, // when any hardware button is pressed on the field computer. hook = new HookKeys(); hook.HookEvent += new HookKeys.HookEventHandler(HookEvent); //hook.Start(); } private void HookEvent(HookEventArgs e, KeyBoardInfo keyBoardInfo) { /* This method is called, when any hardware button is pressed. When a defined button is pressed, foreground windows toggles background color. */ System.Diagnostics.Debug.WriteLine(String.Format("HookEvent called: vkCode={0}", keyBoardInfo.vkCode)); if (keyBoardInfo.vkCode == 123 && e.wParam.ToInt32() == 256) // Home button pressed { System.Diagnostics.Debug.WriteLine("Search button pressed"); ToggleWindow(); } } private void ToggleWindow() { // Bring window of other software to front Color old = this.BackColor; this.BackColor = Color.Blue; this.Refresh(); System.Threading.Thread.Sleep(1000); this.BackColor = old; } private void Form1_Activated(object sender, EventArgs e) { hook.Start(); } private void Form1_Deactivate(object sender, EventArgs e) { hook.Stop(); } } }
If you do not use the above, a system thread is stopped when Form is minimized:
'HookCEtest.exe' (Managed): Loaded 'C:\Program Files (x86)\Microsoft.NET\SDK\CompactFramework\v3.5\Debugger\BCL\System.Drawing.dll' HookEvent called: vkCode=123 HookEvent called: vkCode=123 HookEvent called: vkCode=118 HookEvent called: vkCode=118 HookEvent called: vkCode=123 HookEvent called: vkCode=123 The thread 0xe9ad0012 has exited with code 0 (0x0).
The HookKeys itself does not use any custom thread!